import coin.exchange.base.kr_rest.level_book as level_book_mdl
import coin.exchange.base.kr_rest.public_client_base as pubcb
import coin.exchange.bithumb.kr_rest.native_public_client as npubc
from coin.exchange.bithumb.kr_rest.product import BithumbProduct
from coin.exchange.bithumb.kr_rest.constants import coin_list

from coin.proto.coin_market_query_pb2 import (
    ProductTicker,
    ExchangeTicker,
    ProductKlineElement,
    ProductKline,
)


class BithumbFeedParser(object):
  @staticmethod
  def parse_native_ticker(update_msg, product):
    assert update_msg['status'] == '0000'
    update_msg = update_msg['data']
    return ProductTicker(high=float(update_msg['max_price']),
                         low=float(update_msg['min_price']),
                         last=float(update_msg['closing_price']),
                         bid=float(update_msg['buy_price']),
                         ask=float(update_msg['sell_price']),
                         exchange_timestamp=int(float(update_msg['date']) * (10**6)),
                         volume_24hr=float(update_msg['units_traded']),
                         symbol=product.symbol,
                         native_symbol=product.native_symbol)

  @staticmethod
  def parse_exchange_ticker(update_msg):
    assert update_msg['status'] == '0000'
    update_msg = update_msg['data']
    product_ticker_list = []
    for currency in update_msg:
      if currency == 'date':
        continue
      product = BithumbProduct.FromStrNativeProductNothrow(currency)
      if product is None:
        continue
      product_ticker = ProductTicker(high=float(update_msg[currency]['max_price']),
                                     low=float(update_msg[currency]['min_price']),
                                     last=float(update_msg[currency]['closing_price']),
                                     volume_24hr=float(update_msg[currency]['units_traded_24H']),
                                     symbol=product.symbol,
                                     native_symbol=product.native_symbol)
      product_ticker_list.append(product_ticker)
    assert len(product_ticker_list) > 0
    return ExchangeTicker(exchange="Bithumb", each_ticker=product_ticker_list)

  @staticmethod
  def parse_native_kline(update_msg, product, kline_period, start_time, end_time):
    assert update_msg['status'] == '0000', update_msg
    klines = update_msg['data']
    start_ts = start_time.timestamp()
    end_ts = end_time.timestamp()
    kline_group = []
    for kline in klines:
      kline_ts = kline[0] / 1000
      if kline_ts < start_ts or kline_ts >= end_ts:
        continue
      product_kline = ProductKlineElement(
          kline_timestamp=int(kline_ts * 1e+9),
          open=float(kline[1]),
          close=float(kline[2]),
          high=float(kline[3]),
          low=float(kline[4]),
          volume=float(kline[5]),
      )
      kline_group.append(product_kline)
    assert len(kline_group) > 0
    return ProductKline(
        symbol=product.symbol,
        native_symbol=product.native_symbol,
        exchange='Bithumb',
        market_type='Spot',
        kline_period=kline_period,
        klines=kline_group,
    )

  @staticmethod
  def parse_level_book(update_msg, product):
    level_book = level_book_mdl.LevelBook(product)
    for elem in update_msg['data']['asks']:
      level_elem = level_book_mdl.LevelElement(float(elem['price']), float(elem['quantity']), 0)
      level_book.add_ask(level_elem)
    for elem in update_msg['data']['bids']:
      level_elem = level_book_mdl.LevelElement(float(elem['price']), float(elem['quantity']), 0)
      level_book.add_bid(level_elem)
    level_book.finalize()
    return level_book


class BithumbPublicClient(pubcb.PublicClientBase):
  def __init__(self):
    self.npubc = npubc.BithumbNativePublicClient()

  def query_ticker_impl(self, product):
    base = product.base.native_currency
    quote = product.quote.native_currency
    update = self.npubc.get_ticker(base, quote)
    update.msg = BithumbFeedParser.parse_native_ticker(update.msg, product)
    return update

  def query_exchange_ticker_impl(self):
    update = self.npubc.get_ticker('ALL')
    update.msg = BithumbFeedParser.parse_exchange_ticker(update.msg)
    return update

  def query_history_kline_impl(self, product, kline_period, start_time, end_time):
    base = product.base.native_currency
    quote = product.quote.native_currency
    update = self.npubc.get_history_kline(kline_period, base, quote)
    update.msg = BithumbFeedParser.parse_native_kline(update.msg, product, kline_period, start_time, end_time)
    return update

  def query_level_book_impl(self, product):
    base = product.base.native_currency
    quote = product.quote.native_currency
    update = self.npubc.get_orderbook(base, quote)
    update.msg = BithumbFeedParser.parse_level_book(update.msg, product)
    return update
